#include<vector>
#include<ctime>
#include<cmath>
#include<string>
#include<fstream>
#include"Util.h"
#include"StringPool.h"
#include"variable.h"
#include"DependencyInstance.h"
#include"KBestParseForest.h"
#include"DependencyPipe.h"
#include"DependencyPipe2OGrandChildren.h"
using namespace std;

DependencyPipe2OGrandChildren::DependencyPipe2OGrandChildren(ParserOptions *options) : DependencyPipe(options){}

DependencyPipe2OGrandChildren::~DependencyPipe2OGrandChildren(){}

void DependencyPipe2OGrandChildren::addExtendedFeatures(DependencyInstance *instance, FeatureVector *fv){
	const int instanceLength = instance->length();
	vector<int> *heads = instance->heads;

	for(int i = 0; i < instanceLength; i++){
		if((*heads)[i] == -1 && i != 0){
			continue;
		}

		//left features;
		for(int j = i + 1; j < instanceLength; j++){
			if((*heads)[j] == i){
				for(int k = i + 1; k < instanceLength; k++){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}

		//right features
		for(int j = i - 1; j >= 0; j--){
			if((*heads)[j] == i){
				for(int k = i - 1; k >= 0; k--){
					if(k == j){
						continue;
					}

					if((*heads)[k] == j){
						addGrandFeatures(instance, i, j, k, fv);
						addGChildFeatures(instance, i, k, fv);
					}
				}
			}
		}
	}
}

void DependencyPipe2OGrandChildren::addGChildFeatures(DependencyInstance *instance, int gpar, int ch, FeatureVector *fv){
	string dir3 = gpar > ch ? "RA" : "LA";

	bool flag;

	vector<string*> *pos = instance->postags;

	//POS
	string gpar_pos = *(*pos)[gpar];
	string ch_pos = *(*pos)[ch];

	vector<string*> *cpos = instance->cpostags;
	//CPOS
	string gpar_cpos = *(*cpos)[gpar];
	string ch_cpos = *(*cpos)[ch];

	//FORMS
	vector<string*> *forms = instance->forms;
	string gpar_form = *(*forms)[gpar];
	string ch_form = *(*forms)[ch];
	

	string tmp = "GCH_PAIR=" + gpar_pos + "_" + ch_pos + "_" + dir3;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_CPAIR=" + gpar_cpos + "_" + ch_cpos + "_" + dir3;
	}
	else{
		tmp = "GCH_CPAIR=" + gpar_cpos + "_" + ch_cpos + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_WPAIR=" + gpar_form + "_" + ch_form + "_" + dir3;
	}
	else{
		tmp = "GCH_WPAIR=" + gpar_form + "_" + ch_form + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_WPAIRA=" + gpar_form + "_" + ch_pos + "_" + dir3;
	}
	else{
		tmp = "GCH_WPAIRA=" + gpar_form + "_" + ch_pos + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_WPAIRB=" + gpar_pos + "_" + ch_form + "_" + dir3;
	}
	else{
		tmp = "GCH_WPAIRB=" + gpar_pos + "_" + ch_form + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_WPAIRC=" + gpar_form + "_" + ch_cpos + "_" + dir3;
	}
	else{
		tmp = "GCH_WPAIRC=" + gpar_form + "_" + ch_cpos + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_WPAIRD=" + gpar_cpos + "_" + ch_form + "_" + dir3;
	}
	else{
		tmp = "GCH_WPAIRD=" + gpar_cpos + "_" + ch_form + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_PAIR=" + gpar_pos + "_" + ch_pos;
	}
	else{
		tmp = "AGCH_PAIR=" + gpar_pos + "_" + ch_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_CPAIR=" + gpar_cpos + "_" + ch_cpos;
	}
	else{
		tmp = "AGCH_CPAIR=" + gpar_cpos + "_" + ch_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_WPAIR=" + gpar_form + "_" + ch_form;
	}
	else{
		tmp = "AGCH_WPAIR=" + gpar_form + "_" + ch_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_WPAIRA=" + gpar_form + "_" + ch_pos;
	}
	else{
		tmp = "AGCH_WPAIRA=" + gpar_form + "_" + ch_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_WPAIRB=" + gpar_pos + "_" + ch_form;
	}
	else{
		tmp = "AGCH_WPAIRB=" + gpar_pos + "_" + ch_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_WPAIRC=" + gpar_form + "_" + ch_cpos;
	}
	else{
		tmp = "AGCH_WPAIRC=" + gpar_form + "_" + ch_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_WPAIRD=" + gpar_cpos + "_" + ch_form;
	}
	else{
		tmp = "AGCH_WPAIRD=" + gpar_cpos + "_" + ch_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	int dist = abs(gpar - ch);
	string distBool = "0";
	if (dist > 1){
		distBool = "1";
	}
	if (dist > 2){
		distBool = "2";
	}
	if (dist > 3){
		distBool = "3";
	}
	if (dist > 4){
		distBool = "4";
	}
	if (dist > 5){
		distBool = "5";
	}
	if (dist > 10){
		distBool = "10";
	}

	tmp = "GCH_PAIR_DIST=" + distBool + "_" + dir3;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_PAIR_DIST=" + distBool;
	}
	else{
		tmp = "AGCH_PAIR_DIST=" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_PAIR_DIST=" + gpar_pos + "_" + ch_pos + "_" + distBool + "_" + dir3;
	}
	else{
		tmp = "GCH_PAIR_DIST=" + gpar_pos + "_" + ch_pos + "_" + distBool + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_PAIR_DIST=" + gpar_pos + "_" + ch_pos + "_" + distBool;
	}
	else{
		tmp = "AGCH_PAIR_DIST=" + gpar_pos + "_" + ch_pos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "GCH_CPAIR_DIST=" + gpar_cpos + "_" + ch_cpos + "_" + distBool + "_" + dir3;
	}
	else{
		tmp = "GCH_CPAIR_DIST=" + gpar_cpos + "_" + ch_cpos + "_" + distBool + "_" + dir3;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "AGCH_CPAIR_DIST=" + gpar_cpos + "_" + ch_cpos + "_" + distBool;
	}
	else{
		tmp = "AGCH_CPAIR_DIST=" + gpar_cpos + "_" + ch_cpos + "_" + distBool;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe2OGrandChildren::addGrandFeatures(DependencyInstance *instance, int gpar, int par, int ch, FeatureVector *fv){

	string dir1 = gpar > par ? "RA" : "LA";
	string dir2 = par > ch ? "RA" : "LA";

	bool flag;

	vector<string*> *pos = instance->postags;

	//POS
	string gpar_pos = *(*pos)[gpar];
	string par_pos = *(*pos)[par];
	string ch_pos = *(*pos)[ch];

	string pGrand_pos = gpar_pos + "_" + par_pos + "_" + ch_pos;

	string tmp = "POS_GRAND=" + pGrand_pos + "_" + dir1 + "_" + dir2;
	string *feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APOS_GRAND=" + pGrand_pos;
	}
	else{
		tmp = "APOS_GRAND=" + pGrand_pos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BPOS_GRAND=" + pGrand_pos + "_" + dir1;
	}
	else{
		tmp = "BPOS_GRAND=" + pGrand_pos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CPOS_GRAND=" + pGrand_pos + "_" + dir2;
	}
	else{
		tmp = "CPOS_GRAND=" + pGrand_pos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	vector<string*> *cpos = instance->cpostags;

	//CPOS
	string gpar_cpos = *(*cpos)[gpar];
	string par_cpos = *(*cpos)[par];
	string ch_cpos = *(*cpos)[ch];

	string pGrand_cpos = gpar_cpos + "_" + par_cpos + "_" + ch_cpos;

	tmp = "CPOS_GRAND=" + pGrand_cpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "ACPOS_GRAND=" + pGrand_cpos;
	}
	else{
		tmp = "ACPOS_GRAND=" + pGrand_cpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BCPOS_GRAND=" + pGrand_cpos + "_" + dir1;
	}
	else{
		tmp = "BCPOS_GRAND=" + pGrand_cpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CCPOS_GRAND=" + pGrand_cpos + "_" + dir2;
	}
	else{
		tmp = "CCPOS_GRAND=" + pGrand_cpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}


	//FORMS
	vector<string*> *forms = instance->forms;
	string gpar_form = *(*forms)[gpar];
	string par_form = *(*forms)[par];
	string ch_form = *(*forms)[ch];
	
	string pGrand_form = gpar_form + "_" + par_form + "_" + ch_form;

	tmp = "FORM_GRAND=" + pGrand_form + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AFORM_GRAND=" + pGrand_form;
	}
	else{
		tmp = "AFORM_GRAND=" + pGrand_form;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BFORM_GRAND=" + pGrand_form + "_" + dir1;
	}
	else{
		tmp = "BFORM_GRAND=" + pGrand_form + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CFORM_GRAND=" + pGrand_form + "_" + dir2;
	}
	else{
		tmp = "CFORM_GRAND=" + pGrand_form + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	string gpar_b = gpar_pos + "[" + gpar_form + "]";
	string par_b = par_pos + "[" + par_form + "]";
	string ch_b = ch_pos + "[" + ch_form + "]";

	//POS-FORMS
	string pGrand_fpos = gpar_pos + "_" + par_b + "_" + ch_pos;
	tmp = "PFPOS_GRAND=" + pGrand_fpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APFPOS_GRAND=" + pGrand_fpos;
	}
	else{
		tmp = "APFPOS_GRAND=" + pGrand_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BPFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
	}
	else{
		tmp = "BPFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CPFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
	}
	else{
		tmp = "CPFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pGrand_fpos = gpar_b + "_" + par_pos + "_" + ch_pos;
	tmp = "GFPOS_GRAND=" + pGrand_fpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AGFPOS_GRAND=" + pGrand_fpos;
	}
	else{
		tmp = "AGFPOS_GRAND=" + pGrand_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BGFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
	}
	else{
		tmp = "BGFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CGFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
	}
	else{
		tmp = "CGFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pGrand_fpos = gpar_pos + "_" + par_pos + "_" + ch_b;
	tmp = "QFPOS_GRAND=" + pGrand_fpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AQFPOS_GRAND=" + pGrand_fpos;
	}
	else{
		tmp = "AQFPOS_GRAND=" + pGrand_fpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BQFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
	}
	else{
		tmp = "BQFPOS_GRAND=" + pGrand_fpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CQFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
	}
	else{
		tmp = "CQFPOS_GRAND=" + pGrand_fpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	//CPOS-FORMS
	string gpar_cb = gpar_cpos + "[" + gpar_form + "]";
	string par_cb = par_cpos + "[" + par_form + "]";
	string ch_cb = ch_cpos + "[" + ch_form + "]";

	string pGrand_fcpos = gpar_cpos + "_" + par_cb + "_" + ch_cpos;
	tmp = "PFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "APFCPOS_GRAND=" + pGrand_fcpos;
	}
	else{
		tmp = "APFCPOS_GRAND=" + pGrand_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BPFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
	}
	else{
		tmp = "BPFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CPFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
	}
	else{
		tmp = "CPFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pGrand_fcpos = gpar_cb + "_" + par_cpos + "_" + ch_cpos;
	tmp = "GFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AGFCPOS_GRAND=" + pGrand_fcpos;
	}
	else{
		tmp = "AGFCPOS_GRAND=" + pGrand_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BGFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
	}
	else{
		tmp = "BGFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CGFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
	}
	else{
		tmp = "CGFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}

	pGrand_fcpos = gpar_cpos + "_" + par_cpos + "_" + ch_cb;
	tmp = "QFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1 + "_" + dir2;
	feat = pool->get(tmp);
	flag = add(feat, fv);
	if(flag){
		*feat = "AQFCPOS_GRAND=" + pGrand_fcpos;
	}
	else{
		tmp = "AQFCPOS_GRAND=" + pGrand_fcpos;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "BQFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
	}
	else{
		tmp = "BQFCPOS_GRAND=" + pGrand_fcpos + "_" + dir1;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		*feat = "CQFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
	}
	else{
		tmp = "CQFCPOS_GRAND=" + pGrand_fcpos + "_" + dir2;
		feat = pool->get(tmp);
	}
	flag = add(feat, fv);
	if(flag){
		pool->push_back(feat);
	}
}

void DependencyPipe2OGrandChildren::writeExtendedFeatures(DependencyInstance *instance, ObjectWriter &out){
	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector prodFV = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &prodFV);
				int *keys = prodFV.keys();
				out.writeArray(keys, (int)(prodFV.size()));
				delete[](keys);
			}
		}
	}
	out.writeInt(-3);

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector prodFV = FeatureVector();
			addGChildFeatures(instance, w1, w2, &prodFV);
			int *keys = prodFV.keys();
			out.writeArray(keys, (int)(prodFV.size()));
			delete[](keys);
		}
	}
	out.writeInt(-3);
}

DependencyInstance* DependencyPipe2OGrandChildren::readInstance(ObjectReader &in, int length, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_grands, vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	// Get production crap.
	for (int w1 = 0; w1 < length; w1++) {
		for (int w2 = w1 + 1; w2 < length; w2++) {
			for (int ph = 0; ph < 2; ph++) {
				int *keys = NULL;
				int size = in.readArray(keys);
				probs[w1][w2][ph] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	int last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	if (labeled) {
		for (int w1 = 0; w1 < length; w1++) {
			int len = (int)(types.size());
			for (int t = 0; t < len; t++) {
				for (int ph = 0; ph < 2; ph++) {
					for (int ch = 0; ch < 2; ch++) {
						int *keys = NULL;
						int size = in.readArray(keys);
						nt_probs[w1][t][ph][ch] = getScore(params->parameters, keys, size);
						delete[](keys);
					}
				}
			}
		}
		last = in.readInt();
		if (last != -3) {
			cout<<"Error reading file."<<endl;
			exit(0);
		}
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				if(w3 == w2){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				int *keys = NULL;
				int size = in.readArray(keys);
				probs_grands[w1][w2][w3] = getScore(params->parameters, keys, size);
				delete[](keys);
			}
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			int *keys = NULL;
			int size = in.readArray(keys);
			probs_gchs[w1][w2] = getScore(params->parameters, keys, size);
			delete[](keys);
		}
	}
	last = in.readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	int *keys = NULL;
	int size = in.readArray(keys);
	FeatureVector* nfv = new FeatureVector();
	nfv->construct(keys, size);
	delete[](keys);
	last = in.readInt();
	if (last != -4) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	DependencyInstance* marshalledDI = new DependencyInstance();
	marshalledDI->readObject(in);
	marshalledDI->setFeatureVector(nfv);

	last = in.readInt();
	if (last != -1) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}
	return marshalledDI;
}

void DependencyPipe2OGrandChildren::fillFeatureVectors(DependencyInstance *instance, std::vector<vector<vector<double> > > &probs, std::vector<vector<vector<double> > > &probs_grands, vector<vector<double> > &probs_gchs, std::vector<vector<vector<vector<double> > > > &nt_probs, Parameters *params){
	((DependencyPipe*)this)->fillFeatureVectors(instance, probs, nt_probs, params);

	const int instanceLength = instance->length();

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			for(int w3 = w1 + 1; w3 < instanceLength; w3++){
				if(w3 == w2){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				FeatureVector fv = FeatureVector();
				addGrandFeatures(instance, w1, w2, w3, &fv);
				double prodProb = params->getScore(&fv);
				probs_grands[w1][w2][w3] = prodProb;
			}
		}
	}

	for(int w1 = 0; w1 < instanceLength; w1++){
		for(int w2 = w1 + 1; w2 < instanceLength; w2++){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			FeatureVector fv = FeatureVector();
			addGChildFeatures(instance, w1, w2, &fv);
			double prodProb = params->getScore(&fv);
			probs_gchs[w1][w2] = prodProb;
		}
	}
}
